home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
DCLAP 6d
/
dclap6d
/
network
/
ncsasock
/
sock_std.c
< prev
next >
Wrap
Text File
|
1996-07-05
|
9KB
|
565 lines
/*
* BSD-style socket emulation library for the Mac
* Original author: Tom Milligan
* Current author: Charlie Reiman - creiman@ncsa.uiuc.edu
*
* This source file is placed in the public domian.
* Any resemblance to NCSA Telnet, living or dead, is purely coincidental.
*
* National Center for Supercomputing Applications
* 152 Computing Applications Building
* 605 E. Springfield Ave.
* Champaign, IL 61820
*/
/*
* A really hacked up stdio interface for the MacTCP socket library
*
* routines:
*
* fdopen
* fileno
* fgetc
* ungetc
* fread
* fputc
* fwrite
* fprintf
* fflush
* fclose
* ferror
* feof
* clearerr
*
* hacks:
*
* the stdio data are stored in the socket descriptor. fdopen() calls
* simply return a pointer to the descriptor. The first call per
* socket initializes stdio for both read and write. (The "rw"
* parameter to fdopen() is ignored.) The first fclose() will destroy
* all stdio streams open on the socket.
*
* ungetc will return EOF if the buffer is full.
*
* printf uses a fixed size buffer to build the message.
*
* non-blocking i/o
*
* all read operations which would block return EOF with errno set
* to EWOULDBLOCK courtesy of the read() call.
*
* write operations hide the EINPROGRESS 'error' from the write()
* call, but generate EALREADY when a second operation is attempted.
*
* NOTE: the write() call ties up the stdio buffer until it finishes.
*
* How to code a write operation....
*
* for(;;)
* {
* errno = 0;
* if (s_fprintf(stream, blah, blah) != EOF)
* break;
*
* if (errno == EALREADY)
* {
* Handle_Mac_Events();
* continue;
* }
* else
* {
* a real error ...
* }
* }
*
* How to code a read ...
*
* for(;;)
* {
* errno = 0;
* c = s_fgetc(inFile);
* if (c != EOF)
* break;
* if (errno == EWOULDBLOCK || errno == EALREADY)
* {
* Handle_Mac_Events();
* continue;
* }
* else if (errno == 0)
* {
* a real end of file ...
* }
* else
* {
* a real error ...
* }
* }
*/
#ifdef USEDUMP
# pragma load "Socket.dump"
#else
# include <Events.h>
# include <Memory.h>
# include <Types.h>
# include <Stdio.h>
# include <s_types.h>
# include <neti_in.h>
#ifdef COMP_CODEWAR
#define NOWAY
#undef EDOM
#undef ERANGE
#endif
# include <neterrno.h>
# include <s_socket.h>
# include <s_time.h>
# include <s_uio.h>
# include "sock_str.h"
# include "sock_int.h"
/*# include <sock_ext.h>*/
# include <unixlib.h>
#endif
#include <StdArg.h>
extern SocketPtr sockets;
extern SpinFn aspinroutine;
/*
* tuneable constants
*/
#define SOCK_IOINBUF_SIZE 128 /* Size of stdio input buffer */
#define SOCK_IOOUTBUF_SIZE 128 /* Size of stdio output buffer */
static struct timeval select_poll = {0,0};
/*
* s_fdopen() - open a stdio stream on a socket
*/
Ptr s_fdopen(
int fd,
char *type)
{
#pragma unused(type)
SocketPtr sp;
#if SOCK_STDIO_DEBUG >= 3
dprintf("s_fdopen: opening on fd %d\n",fd);
#endif
if (! sock_good_fd(fd))
{
(void)sock_err(EBADF);
return(NULL);
}
sp = sockets+fd;
if (is_stdio(sp))
return((Ptr)sp);
sp->inbuf = (char *)NewPtr(SOCK_IOINBUF_SIZE);
if (sp->inbuf == NULL)
{
errno = ENOMEM;
return(NULL);
}
sp->outbuf = (char *)NewPtr(SOCK_IOOUTBUF_SIZE);
if (sp->outbuf == NULL)
{
DisposPtr(sp->inbuf);
errno = ENOMEM;
return(NULL);
}
sp->inbufptr = sp->inbuf;
sp->inbufcount = 0;
sp->outbufptr = sp->outbuf;
sp->outbufcount = 0;
sp->ioerr = false;
sp->ioeof = false;
return((Ptr)sp);
}
/*
* s_fileno()
*/
int s_fileno(
SocketPtr sp)
{
#if SOCK_STDIO_DEBUG >= 3
dprintf("s_fileno: on FILE * %08x\n",sp);
#endif
if (! is_stdio(sp))
{
return(sock_err(EBADF));
return(EOF);
}
#if SOCK_STDIO_DEBUG >= 5
dprintf(" returning fd %d\n",sp->fd);
#endif
return(sp->fd);
}
static int stdio_read(
SocketPtr sp,
char *buffer,
int buflen);
/*
* s_fgetc()
*
*/
int s_fgetc(
SocketPtr sp)
{
char c;
if (stdio_read(sp, &c, 1) != 1)
return(EOF);
return(c);
}
/*
* s_ungetc()
*
*/
int s_ungetc(
char c,
SocketPtr sp)
{
#if SOCK_STDIO_DEBUG >=3
dprintf("s_ungetc: %08x\n",sp);
#endif
if (! is_stdio(sp))
{
(void)sock_err(EBADF);
return(EOF);
}
if (sp->ioeof) /* Once an EOF; Always an EOF */
return(EOF);
/*
* Pop onto buffer, if there is room.
*/
if (sp->inbufptr == sp->inbuf)
return(EOF);
else
{
*(sp->inbufptr++) = c;
sp->inbufcount++;
return(0);
}
}
/*
* s_fread()
*/
int s_fread(
char *buffer,
int size,
int nitems,
SocketPtr sp)
{
return(stdio_read(sp, buffer, size*nitems));
}
/*
* stdio_read()
*
* Buffered i/o. Read buflen chars into buf.
* Returns length read, EOF on error.
*/
static int stdio_read(
SocketPtr sp,
char *buffer,
int buflen)
{
unsigned long tocopy;
Ptr buf;
unsigned long len;
int cache = false; /* a flag ===> read into sp->inbuf */
#if SOCK_STDIO_DEBUG >=3
dprintf("stdio_read: %08x for %d bytes\n",sp,buflen);
#endif
if (! is_stdio(sp))
{
(void)sock_err(EBADF);
return(EOF);
}
if (sp->ioeof) /* Once an EOF; Always an EOF */
return(EOF);
/*
* return already buffered characters
*/
if (sp->inbufcount != 0)
{
tocopy = min(sp->inbufcount, buflen);
bcopy(sp->inbufptr, buffer, tocopy);
sp->inbufptr += tocopy;
sp->inbufcount -= tocopy;
return(tocopy);
}
if (buflen > SOCK_IOINBUF_SIZE)
{
/*
* Read into user's buffer
*/
buf = buffer;
len = buflen;
}
else
{
/*
* Read into stdio buffer
*/
cache = true;
buf = sp->inbuf;
len = SOCK_IOINBUF_SIZE;
}
len = s_read(sp->fd, buf, len);
switch(len)
{
case -1:
sp->ioerr = true;
return(EOF);
case 0:
sp->ioeof = true;
return(EOF);
}
if (cache)
{
tocopy = min(buflen, len);
bcopy(sp->inbuf, buffer, tocopy); /* copy to client's buffer */
sp->inbufcount = len - tocopy;
sp->inbufptr = sp->inbuf + tocopy;
return(tocopy);
}
return(len);
}
static int stdio_write(
SocketPtr sp,
char *buffer,
unsigned long buflen);
/*
* s_fputc()
*
*/
int s_fputc(
char c,
SocketPtr sp)
{
if (stdio_write(sp, &c, 1) == EOF)
return(EOF);
return(c);
}
/*
* s_fprintf()
* Modified to use StdArg macros by Charlie Reiman
* Wednesday, August 8, 1990 2:52:31 PM
*
*/
int s_fprintf(
SocketPtr sp,
char *fmt,
...)
{
va_list nextArg;
int len;
char buf[1000];
va_start(nextArg,fmt);
(void) vsprintf(buf,fmt,nextArg);
len = strlen(buf);
return(stdio_write(sp, buf, len));
}
/*
* s_fwrite()
*
*/
int s_fwrite(
char *buffer,
int size,
int nitems,
SocketPtr sp)
{
return(stdio_write(sp, buffer, size*nitems));
}
/*
* stdio_write()
*
* Buffered i/o. Move buflen chars into stdio buf., writing out as necessary.
* Returns # of characters written, or EOF.
*/
static int stdio_write(
SocketPtr sp,
char *buffer,
unsigned long buflen)
{
long buffree;
struct iovec iov[2];
#if SOCK_STDIO_DEBUG >=3
dprintf("stdio_write: %08x for %d bytes\n",sp,buflen);
#endif
if (! is_stdio(sp))
{
(void) sock_err(EBADF);
return(EOF);
}
/* will the new stuff fit in the buffer? */
buffree = SOCK_IOOUTBUF_SIZE - sp->outbufcount;
if (buflen < buffree)
{
/* yes...add it in */
bcopy(buffer, sp->outbufptr, buflen);
sp->outbufptr += buflen;
sp->outbufcount += buflen;
return(buflen);
}
else
{
/* no...send both buffers now */
iov[0].iov_len = sp->outbufcount;
iov[0].iov_base = sp->outbuf;
iov[1].iov_len = buflen;
iov[1].iov_base = buffer;
/* hide the 'error' generated by a non-blocking write */
if (s_writev(sp->fd,&iov[0],2) < 0 && errno != EINPROGRESS)
{
sp->ioerr = true;
return(EOF);
}
sp->outbufptr = sp->outbuf;
sp->outbufcount = 0;
return(buflen);
}
}
/*
* s_fflush()
*
*/
int s_fflush(
SocketPtr sp)
{
#if SOCK_STDIO_DEBUG >=3
dprintf("s_fflush: %08x\n",sp);
#endif
if (! is_stdio(sp))
{
(void)sock_err(EBADF);
return(EOF);
}
if (sp->outbufcount == 0)
return(0);
if (s_write(sp->fd,sp->outbuf,sp->outbufcount) < 0)
/* hide the 'error' generated by non-blocking I/O */
if (errno != EINPROGRESS)
{
sp->ioerr = true;
return(EOF);
}
sp->outbufptr = sp->outbuf;
sp->outbufcount = 0;
return(0);
}
/*
* s_fclose() - close the stdio stream AND the underlying socket
*/
int s_fclose(
SocketPtr sp)
{
#if SOCK_STDIO_DEBUG >=3
dprintf("s_fclose: %08x\n",sp);
#endif
if (s_fflush(sp) == EOF) /* flush validates sp */
return(EOF);
if (sp->inbuf != NULL) DisposPtr(sp->inbuf);
if (sp->outbuf != NULL) DisposPtr(sp->outbuf);
return(s_close(sp->fd));
}
/*
* s_ferror()
*/
int s_ferror(
SocketPtr sp)
{
if (! is_stdio(sp))
{
(void)sock_err(EBADF);
return(EOF);
}
return(sp->ioerr);
}
/*
* s_feof()
*/
int s_feof(
SocketPtr sp)
{
if (! is_stdio(sp))
{
(void)sock_err(EBADF);
return(EOF);
}
return(sp->ioeof);
}
/*
* s_clearerr()
*/
int s_clearerr(
SocketPtr sp)
{
if (! is_stdio(sp))
{
(void)sock_err(EBADF);
return(EOF);
}
sp->ioerr = false;
sp->ioeof = false;
return (0);
}